<template>
  <el-form
    ref="ruleFormRef"
    inline
    :rules="rules"
    label-width="100px"
    :model="model"
    v-bind="formAttrs"
    :validate-on-rule-change="false"
    @submit.prevent
  >
    <draggable v-model="displayOptions" item-key="prop" group="people" class="select-box" @change="draggableChange">
      <template #item="{ element, index }">
        <el-form-item
          :key="element.prop"
          :prop="element.prop"
          :label="setDisplayLabel(element.label)"
          @click.prevent.stop="itemClick(element, index)"
          :class="[selectedIndex === index ? 'selected-item' : '']"
        >
          <template v-if="element.type === 'cascader'">
            <!-- cascader 有默认插槽无法兼容 -->
            <component
              :is="`el-${element.type}`"
              v-bind="element.attrs"
              :style="setItemStyle(element)"
              v-model="model[element.prop]"
              :placeholder="setPlaceholder(element)"
              @change="allFun(element, 'changeMethod')"
              @input="allFun(element, 'inputMethod')"
            >
            </component>
          </template>
          <component
            v-else
            :is="`el-${element.type}`"
            v-bind="element.attrs"
            :style="setItemStyle(element)"
            v-model="model[element.prop]"
            :placeholder="setPlaceholder(element)"
            @change="allFun(element, 'changeMethod')"
            @input="allFun(element, 'inputMethod')"
            @blur="allFun(element, 'blurFunction')"
            @calendar-change="allFun(element, 'calendarChange')"
          >
            <template v-if="element?.children">
              <component
                :is="`el-${child.type}`"
                v-for="child in element.children"
                :key="child.label"
                :value="child.value"
                :label="child.label"
              />
            </template>
          </component>
          <div v-if="selectedIndex === index" class="item-operation">
            <slot name="operationItem" :item="element" :index="index"></slot>
          </div>
        </el-form-item>
      </template>
    </draggable>

    <slot name="formBottom" :scope="model" />

    <div class="flx-justify-end" v-if="saveButton">
      <ElButton @click="cancel">{{ _transitionLanguages('button', 'cancel') }}</ElButton>
      <ElButton type="primary" @click="submitForm()" :loading="loading">
        {{ _transitionLanguages('button', 'save') }}
      </ElButton>
    </div>
  </el-form>
</template>
<script setup lang="ts" name="proForm">
import { OptionsProps, FormProps } from '@/components/ProForm/interface';
import draggable from 'vuedraggable';
import type { FormInstance } from 'element-plus';
import { onBeforeMount, computed, ref, CSSProperties } from 'vue';

// 深拷贝
import { cloneDeep } from 'lodash';
import { useGlobalStore } from '@/stores/modules/global';
import { FormWIdthEnum } from '@/enums';
export interface ProFormProps {
  options: OptionsProps[];
  visible?: boolean;
  formAttrs?: FormProps | any;
  formCols?: number;
  // 是否显示提交按钮
  saveButton?: boolean;
  selectIndex: number;
}
const props = withDefaults(defineProps<ProFormProps>(), {
  options: () => [],
  formCols: 2,
  visible: false,
  saveButton: true,
  selectIndex: -1
});

// 需要显示的表单
let displayOptions = ref([]);

watch(
  () => props.selectIndex,
  value => {
    selectedIndex.value = value;
  }
);

watch(
  () => props.options,
  () => {
    initForm();
    displayOptions.value = props.options;
  }
  // { deep: true, immediate: true }
);

const $emit = defineEmits(['getModel', 'cancel', 'update:visible', 'validateForm', 'update:options']);

const globalStore = useGlobalStore();
const ruleFormRef = ref<FormInstance>();

// 选中的下标
const selectedIndex = ref(0);
// 语言转换
const _transitionLanguages = (v: string, l: string): string => {
  return transitionLanguages(v, l);
};

const loading = computed(() => globalStore.formLoading);

// 验证规则
const rules = computed(() => {
  let r: any = {};
  for (let op of props.options) {
    if (!op?.rules) {
      continue;
    }
    let rules = cloneDeep(op?.rules || []);
    // console.log(rules, 'rules');

    for (let rs of rules) {
      // console.log(rs, 'rs');

      if (!rs?.message || rs?.message === op?.label) {
        rs.message = transitionLanguages('table', op.label) + isSpacing() + transitionLanguages('rules', 'canNotBeEmpty');
      }
    }
    r[op['prop']] = rules || [];
  }
  return r;
});

let model = ref({});

onBeforeMount(() => {
  initForm();
  document.onkeydown = keyupSubmit;
});

const keyupSubmit = (e: KeyboardEvent) => {
  if (e.key === 'Enter') {
    if (!props.visible) {
      return;
    }
    submitForm();
  }
};

const draggableChange = () => $emit('update:options', displayOptions.value);

const initForm = () => {
  model.value = {};

  for (let op of props.options) {
    const { defaultValue, prop } = op;
    // console.log(prop, 'prop');

    model.value[prop] = defaultValue;
  }

  // 将字段给到父级 方便后续字段修改
  $emit('getModel', model.value);
};

const cancel = () => {
  $emit('update:visible', false);
  $emit('cancel', false);
};
const itemClick = (item, index: number) => {
  selectedIndex.value = index;
  // console.log(item, 'item');

  // console.log(1);

  mittBus.emit('crated-form-content', {
    item,
    index
  });
};

const submitForm = async () => {
  return new Promise(async resolve => {
    if (!ruleFormRef.value) return;
    await ruleFormRef.value.validate((valid, fields) => {
      if (valid) {
        $emit('validateForm', model.value);
        globalStore.formLoading = true;
        resolve(model.value);
      } else {
        console.log(fields);
        // reject(fields);
      }
    });
  });
};

const allFun = (item: OptionsProps, fun: 'changeMethod' | 'inputMethod' | 'calendarChange' | 'blurFunction') => {
  console.log(item[fun], 'item[fun]');

  if (typeof item[fun] === 'function') {
    const f: any = item[fun];
    f && f(model.value);
  }
};

// 设置默认占位符
const setPlaceholder = (item: OptionsProps) => {
  let placeholder = item.attrs?.placeholder;

  // 选择类型字段
  const selectTypes = ['select', 'date'];

  const { type, label } = item;

  // 输入框 还是 选择框
  const useType = selectTypes.includes(type) ? 'select' : 'input';
  const p = !placeholder
    ? selectTransitionLanguages(`table`, label, useType)
    : selectTransitionLanguages('placeholder', item.attrs?.placeholder || '', useType);

  return p;
};

// 设置显示的标签
const setDisplayLabel = (label: string) => {
  return transitionLanguages('table', label);
};

// 设置默认 form-item 宽度
const setItemStyle = (item: OptionsProps) => {
  const { style } = item.attrs || {};

  let s: CSSProperties = {};

  // 有自定义样式使用自定义样式
  if (style) {
    s = style;
  }

  // 如果没有设置宽度设置默认form-item 宽度
  if (!s.width) {
    const { width } = style || {};
    s.width = width || FormWIdthEnum.itemCol1;
  }

  return s;
};

defineExpose({
  submitForm,
  ruleFormRef,
  model
});
</script>

<style lang="scss" src="./index.scss"></style>
